import axios from 'axios';
import * as https from 'https';
import { SocksProxyAgent } from 'socks-proxy-agent';
import { configService } from '../utils/config.service';

/**
 * REST API 请求基础服务类
 * 提供通用的 HTTP 请求功能，包括请求配置、错误处理和限速控制
 * 
 */
export class RestApiService {
  protected readonly baseUrl: string;
  protected readonly apiClient: any; // 使用any类型简化
  private requestTimestamps: number[] = [];
  private readonly rateLimitWindow = 2000; // 2秒窗口
  private readonly rateLimitRequests = 20; // 20次请求

  /**
   * 构造函数
   * @param baseUrl API 基础 URL，默认使用配置中的 REST_URL
   * @param options 额外的配置选项
   */
  constructor(baseUrl?: string, options: {
    timeout?: number;
    proxy?: string;
    headers?: Record<string, string>;
  } = {}) {
    const apiConfig = configService.getApiConfig();
    this.baseUrl = baseUrl || apiConfig?.baseUrl || 'https://www.okx.com';

    // 创建 axios 实例
    const axiosConfig: any = {
      baseURL: this.baseUrl,
      timeout: options.timeout || apiConfig?.timeout || 30000,
      headers: {
        'Content-Type': 'application/json',
        ...options.headers
      },
      // 允许自签名证书，避免SSL错误
      httpsAgent: new https.Agent({
        rejectUnauthorized: false
      })
    };

    // 统一处理代理配置
    // 优先级: options.proxy > config.yaml > no proxy
    let proxyToUse: string | undefined = options.proxy;
    if (proxyToUse === undefined) {
      // 如果options未提供，则从全局配置获取, 并处理null
      const proxyFromConfig = configService.getProxy();
      proxyToUse = proxyFromConfig === null ? undefined : proxyFromConfig;
    }

    if (proxyToUse) { // a null value will correctly be falsy
      console.log(`使用代理: ${proxyToUse}`);
      // 处理SOCKS5代理
      if (proxyToUse.includes('socks5')) {
        // 直接使用完整的socks5 URL
        const socksAgent = new SocksProxyAgent(proxyToUse);
        axiosConfig.httpsAgent = socksAgent;
        axiosConfig.httpAgent = socksAgent;
      } else {
        // 处理普通HTTP代理
        const proxyParts = proxyToUse.split(':');
        axiosConfig.proxy = {
          host: proxyParts[0],
          port: parseInt(proxyParts[1] || '8080')
        };
      }
    } else {
      console.log(`不使用代理`);
    }

    // 创建一次apiClient实例，避免重复创建
    this.apiClient = axios.create(axiosConfig);

    // 请求拦截器 - 处理限速
    this.apiClient.interceptors.request.use(async (config: any) => {
      await this.applyRateLimit();
      return config;
    });

    // 响应拦截器 - 处理错误
    this.apiClient.interceptors.response.use(
      (response: any) => response,
      (error: any) => this.handleApiError(error)
    );
  }

  /**
   * 发送 GET 请求
   * @param endpoint API 端点
   * @param params 请求参数
   * @param config Axios 请求配置
   * @returns Promise 包含响应数据
   */
  public async get<T>(
    endpoint: string,
    params?: Record<string, any>,
    config?: any
  ): Promise<T> {
    try {
      // console.log(`发送GET请求: ${endpoint} ${params ? JSON.stringify(params, null, 2) : ''}`);
      const response = await this.apiClient.get(endpoint, {
        ...config,
        params,
      });
      return response.data as T;
    } catch (error) {
      console.error(`GET请求失败: ${endpoint}`, error);
      throw error;
    }
  }

  /**
   * 发送 POST 请求
   * @param endpoint API 端点
   * @param data 请求体数据
   * @param config Axios 请求配置
   * @returns Promise 包含响应数据
   */
  protected async post<T>(
    endpoint: string,
    data?: any,
    config?: any
  ): Promise<T> {
    try {
      console.log(`发送POST请求: ${endpoint} ${data ? JSON.stringify(data, null, 2) : ''}`);
      const response = await this.apiClient.post(endpoint, data, config);
      return response.data as T;
    } catch (error) {
      console.error(`POST请求失败: ${endpoint}`, error);
      throw error;
    }
  }

  /**
   * 处理 API 错误
   * @param error Axios 错误对象
   * @returns 拒绝的 Promise
   */
  private handleApiError(error: any): Promise<never> {
    if (error.response) {
      // 服务器返回了错误状态码
      console.error(
        `API Error: ${error.response.status} - ${JSON.stringify(
          error.response.data
        )}`
      );
    } else if (error.request) {
      // 请求已发送但没有收到响应
      console.error(`No response received: ${error.request}`);

      // 检查是否是超时错误
      if (error.code === 'ECONNABORTED') {
        console.error(`请求超时。可能原因：
1. 网络连接问题
2. 服务器响应时间过长
3. 可能需要使用代理访问OKX API

建议：
- 增加超时时间
- 检查网络连接
- 考虑使用代理服务器`);
      }
    } else {
      // 请求设置时发生错误
      console.error(`Request error: ${error.message}`);
    }

    return Promise.reject(error);
  }

  /**
   * 应用请求限速控制
   * 如果当前请求会超过限速，则等待适当的时间
   */
  private async applyRateLimit(): Promise<void> {
    const now = Date.now();

    // 清除过期的请求时间戳
    this.requestTimestamps = this.requestTimestamps.filter(
      (timestamp) => now - timestamp < this.rateLimitWindow
    );

    if (this.requestTimestamps.length >= this.rateLimitRequests) {
      // 计算需要等待的时间
      const oldestTimestamp = this.requestTimestamps[0];
      const waitTime = this.rateLimitWindow - (now - oldestTimestamp);

      if (waitTime > 0) {
        await new Promise((resolve) => setTimeout(resolve, waitTime));
      }

      // 更新当前时间，因为已经等待了一段时间
      this.requestTimestamps.shift();
    }

    // 添加当前请求的时间戳
    this.requestTimestamps.push(Date.now());
  }

  /**
   * 测试与API服务器的连接
   * @returns Promise 包含测试结果
   */
  async testConnection(): Promise<{ success: boolean; message: string }> {
    try {
      // 尝试访问一个简单的端点
      await this.get<any>('/api/v5/public/time');
      return { success: true, message: '连接成功' };
    } catch (error: any) {
      return {
        success: false,
        message: `连接失败: ${error.message || '未知错误'}`
      };
    }
  }
} 